package model

import (
	"honeyweb/log"
	"fmt"
	"gorm.io/gorm"
)

const (
	SqlQueryWalletForUpdate = "select %s from wallet_accounts where uid = ? for update"
	SqlUpdateWallet = "update wallet_accounts set %s = ? where uid = ?"
)

//账号的钱包信息
type WalletAccount struct {
	Uid int `json:"uid" gorm:"primaryKey";comment:账号id"`
	Gold int64 `json:"gold" gorm:"comment:金币"`
	Diamond int64 `json:"diamond" gorm:"comment:钻石"`
	Score int64 `json:"score" gorm:"comment:积分"`
}

func CreateWalletAccount(db *gorm.DB, w *WalletAccount) error {
	tx := db.Create(w)
	return tx.Error
}

func GetWalletAccount(db *gorm.DB, uid int) *WalletAccount {
	w := &WalletAccount{
		Uid: uid,
	}
	tx := db.Take(w)
	if tx.Error != nil {
		log.S().Errorf("find wallet uid: %d err: %v", uid, tx.Error)
		return nil
	}
	return  w
}

func AddGold(db *gorm.DB, uid int, value int64) *WalletAccount {
	w := &WalletAccount{
		Uid: uid,
	}
	tx := db.Model(w).UpdateColumn("gold", gorm.Expr("gold + ?", value))
	log.S().Debug(tx.RowsAffected)
	if tx.Error != nil || tx.RowsAffected != 1{
		log.S().Errorf("add gold uid: %d err: %v", uid, tx.Error)
		return nil
	}

	return  GetWalletAccount(db, uid )
}

func SubGold(db *gorm.DB, uid int, value int64) *WalletAccount {
	w := &WalletAccount{
		Uid: uid,
	}
	tx := db.Model(w).Where("gold >= ?", value).UpdateColumn("gold", gorm.Expr("gold - ?", value))
	log.S().Debug(tx.RowsAffected)
	if tx.Error != nil || tx.RowsAffected != 1{
		log.S().Errorf("sub gold uid: %d err: %v", uid, tx.Error)
		return nil
	}
	return  GetWalletAccount(db, uid )
}

//减少用户金币，不足，减到账号为0， 返回账号及实际的值
func SubMutableGold(db *gorm.DB, uid int, value int64) (*WalletAccount, int64) {
	tx := db.Begin()
	var left int64
	err := tx.Raw(fmt.Sprintf(SqlQueryWalletForUpdate,"gold"), uid).Scan(&left).Error
	if err != nil {
		log.S().Errorf("sub mutalbe gold uid: %d err: %v", uid, err)
		return nil, 0
	}
	if left < value {
		log.S().Infof("uid:%d gold left:%d < value:%d", uid, left, value)
		value = left
	}
	tx.Exec(fmt.Sprintf(SqlUpdateWallet,"gold"), gorm.Expr("gold - ?", value), uid)
	tx.Commit()
	return GetWalletAccount(db, uid), value
}

func AddDiamond(db *gorm.DB, uid int, value int64) *WalletAccount {
	w := &WalletAccount{
		Uid: uid,
	}
	tx := db.Model(w).UpdateColumn("diamond", gorm.Expr("diamond + ?", value))
	log.S().Debug(tx.RowsAffected)
	if tx.Error != nil || tx.RowsAffected != 1{
		log.S().Errorf("add diamond uid: %d err: %v", uid, tx.Error)
		return nil
	}
	return  GetWalletAccount(db, uid )
}

func SubDiamond(db *gorm.DB, uid int, value int64) *WalletAccount {
	w := &WalletAccount{
		Uid: uid,
	}
	tx := db.Model(w).Where("diamond >= ?", value).UpdateColumn("diamond", gorm.Expr("diamond - ?", value))
	log.S().Debug(tx.RowsAffected)
	if tx.Error != nil || tx.RowsAffected != 1{
		log.S().Errorf("sub diamond uid: %d err: %v", uid, tx.Error)
		return nil
	}
	return  GetWalletAccount(db, uid )
}

//减少用户钻石不足，减到账号为0， 返回账号及实际的值
func SubMutableDiamond(db *gorm.DB, uid int, value int64) (*WalletAccount, int64) {
	tx := db.Begin()
	var left int64
	err := tx.Raw(fmt.Sprintf(SqlQueryWalletForUpdate,"diamond"), uid).Scan(&left).Error
	if err != nil {
		log.S().Errorf("sub mutalbe diamond uid: %d err: %v", uid, err)
		return nil, 0
	}
	if left < value {
		log.S().Infof("uid:%d diamond left:%d < value:%d", uid, left, value)
		value = left
	}
	tx.Exec(fmt.Sprintf(SqlUpdateWallet,"diamond"), gorm.Expr("diamond - ?", value), uid)
	tx.Commit()
	return GetWalletAccount(db, uid), value
}


func AddScore(db *gorm.DB, uid int, value int64) *WalletAccount {
	w := &WalletAccount{
		Uid: uid,
	}
	tx := db.Model(w).UpdateColumn("score", gorm.Expr("score + ?", value))
	log.S().Debug(tx.RowsAffected)
	if tx.Error != nil || tx.RowsAffected != 1{
		log.S().Errorf("add score uid: %d err: %v", uid, tx.Error)
		return nil
	}

	return  GetWalletAccount(db, uid )
}

func SubScore(db *gorm.DB, uid int, value int64) *WalletAccount {
	w := &WalletAccount{
		Uid: uid,
	}
	tx := db.Model(w).Where("score >= ?", value).UpdateColumn("score", gorm.Expr("score - ?", value))
	log.S().Debug(tx.RowsAffected)
	if tx.Error != nil || tx.RowsAffected != 1{
		log.S().Errorf("sub score uid: %d err: %v", uid, tx.Error)
		return nil
	}
	return  GetWalletAccount(db, uid )
}

//减少用户积份不足，减到账号为0， 返回账号及实际的值
func SubMutableScore(db *gorm.DB, uid int, value int64) (*WalletAccount, int64) {
	tx := db.Begin()
	var left int64
	err := tx.Raw(fmt.Sprintf(SqlQueryWalletForUpdate,"score"), uid).Scan(&left).Error
	if err != nil {
		log.S().Errorf("sub mutalbe score uid: %d err: %v", uid, err)
		return nil, 0
	}
	if left < value {
		log.S().Infof("uid:%d score left:%d < value:%d", uid, left, value)
		value = left
	}
	tx.Exec(fmt.Sprintf(SqlUpdateWallet,"score"), gorm.Expr("score - ?", value), uid)
	tx.Commit()
	return GetWalletAccount(db, uid), value
}



